package cn.nexttec.noteplayer.common

import android.content.Context
import android.content.SharedPreferences
import cn.nexttec.noteplayer.models.NoteFile
import cn.nexttec.noteplayer.models.VideoFileInfo
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import java.util.Date

/**
 *
 * apply() vs commit() 对比
方法	        是否同步	是否有返回值	是否线程安全	可能丢失数据	        使用场景
apply()	    ❌ 异步	❌ 无返回值	✅ 是	    ✅ 是（如崩溃、关机）	推荐用于大多数普通场景
commit()	✅ 同步	✅ 有返回值	✅ 是	    ❌ 否（保存立即完成）	推荐用于重要数据保存

 */
class Preference(val context: Context) {


    var sharedPreferences: SharedPreferences? = null
    var gson: Gson = GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create()
    private var editor: SharedPreferences.Editor? = null


    companion object {
        private const val SORT = "sort"
        private const val ENABLE_AUDIO = "enable_audio"
        private const val ENABLE_EYE_TRACE = "eye_trace"
        private const val PLAYLIST = "playlist"
        private const val MOVIE_MODE = "movie_mode"
        private const val HIDE_PRIVATE = "hide_private"
        private const val ENABLE_PRIVATE = "enable_private"
        private const val SKIP_ANIMATION = "skip_animation"
        private const val AUTO_PLAY_NEXT_VIDEO = "auto_play_next_video"
        private const val PASSWORD = "password"
        private const val KEEP_MUSIC = "keep_music"
        private const val EYE_TRACE = "eye_trace"
        private const val MODEL_PATH = "model_path"

        // 应用全局变量
        var noteFile: NoteFile? = null

        private var _instance: Preference? = null

        /**
         * 初始化 Preference 工具类，必须在 Application 中调用一次
         */
        fun init(context: Context) {
            if (_instance == null) {
                _instance = Preference(context).also { preference ->
                    preference.sharedPreferences =
                        context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
                            .also {
                                preference.editor = it.edit()
                            }
                }
            }
        }

        /**
         * 获取 Preference 单例
         */
        fun getInstance(): Preference {
            if (_instance == null) {
                throw NullPointerException("请先使用 init(context) 方法初始化 Preference")
            }
            return _instance!!
        }
    }

    /**
     * 存储数据，如果是原生类型则直接存储，否则使用 Gson 转换为 JSON 字符串存储
     */
    fun put(key: String, value: Any?) {
        if (sharedPreferences == null || editor == null) return
        if (value == null) {
            remove(key)
        } else {
            when (value) {
                is String -> editor?.putString(key, value)
                is Int -> editor?.putInt(key, value)
                is Boolean -> editor?.putBoolean(key, value)
                is Float -> editor?.putFloat(key, value)
                is Long -> editor?.putLong(key, value)
                is Double -> editor?.putString(key, value.toString()) // Double 转为字符串存储
                is Date -> editor?.putString(key, gson.toJson(value)) // Date 转为 JSON 字符串
                else -> editor?.putString(key, gson.toJson(value))    // 其他对象也用 JSON 序列化
            }
            editor?.commit()
        }
    }

    /**
     * 获取指定类型的数据，支持基本类型和对象
     *
     * Kotlin 编译器限制：inline + reified 函数无法访问 private/internal 成员，
     * 所以所有逻辑只能保留在 public inline 函数中，避免“Public-API inline function cannot access non-public-API”错误。
     *
     * 如果未来 Kotlin 支持 inline 调用 internal/private 函数，
     * 可考虑将类型判断和 JSON 解析逻辑提取到内部函数中以优化结构。
     */
    inline fun <reified T> get(
        key: String,
        default: T? = null,
    ): T? {
        if (sharedPreferences == null) return default


        return when (T::class) {
            String::class -> sharedPreferences?.getString(key, default as? String) as T?
            Int::class -> sharedPreferences?.getInt(key, default as? Int ?: 0) as T?
            Boolean::class -> sharedPreferences?.getBoolean(key, default as? Boolean ?: false) as T?
            Float::class -> sharedPreferences?.getFloat(key, default as? Float ?: 0f) as T?
            Long::class -> sharedPreferences?.getLong(key, default as? Long ?: 0L) as T?
            Double::class -> sharedPreferences?.getString(key, null)?.toDoubleOrNull() as T?
            Date::class -> sharedPreferences?.getString(key, null)?.let {
                gson.fromJson(it, Date::class.java)
            } as T?

            else -> {
                val json = sharedPreferences?.getString(key, null)
                if (!json.isNullOrEmpty()) {
                    try {
                        gson.fromJson(json, T::class.java)
                    } catch (e: Exception) {
                        default
                    }
                } else default
            }
        }
    }

    /**
     * 移除某个键对应的数据
     */
    fun remove(key: String) {
        editor?.remove(key)?.commit()
    }

    /**
     * 清空所有保存的数据
     */
    fun clear() {
        editor?.clear()?.commit()
    }

    var isScanfinished: Boolean = false

    var enableAudioMode: Boolean
        get() = sharedPreferences!!.getBoolean(ENABLE_AUDIO, false)
        set(value) {
            editor!!.putBoolean(ENABLE_AUDIO, value).commit()
        }

    var enableEyeTrace: Boolean
        get() = sharedPreferences!!.getBoolean(ENABLE_EYE_TRACE, false)
        set(value) {
            editor!!.putBoolean(ENABLE_EYE_TRACE, value).commit()
        }

    var playList: HashMap<Int, String>?
        get() {
            val string = sharedPreferences!!.getString(PLAYLIST, "")
            return if (string.isNullOrEmpty()) null else string.parse<HashMap<Int, String>>()
        }
        set(value) {
            if (value.isNullOrEmpty()) {
                editor!!.remove(PLAYLIST).commit()
            } else {
                editor!!.putString(PLAYLIST, value.gson()).commit()
            }
        }


    var sortMethod: Int
        get() = sharedPreferences!!.getInt(SORT, 0)
        set(value) {
            editor!!.putInt(SORT, value).commit()
        }

    var isMovieMode: Boolean
        get() {
            return sharedPreferences!!.getBoolean(MOVIE_MODE, false)
        }
        set(value) {
            editor!!.putBoolean(MOVIE_MODE, value).commit()
        }

    var isHidePrivateFile: Boolean
        get() {
            return sharedPreferences!!.getBoolean(HIDE_PRIVATE, false)
        }
        set(value) {
            editor!!.putBoolean(HIDE_PRIVATE, value).commit()
        }


    var enablePrivate: Boolean
        get() {
            return sharedPreferences!!.getBoolean(ENABLE_PRIVATE, false)
        }
        set(value) {
            editor!!.putBoolean(ENABLE_PRIVATE, value).commit()
        }


    var isSkipAnimation: Boolean
        get() {
            return sharedPreferences!!.getBoolean(SKIP_ANIMATION, false)
        }
        set(value) {
            editor!!.putBoolean(SKIP_ANIMATION, value).commit()
        }

    var isAutoPlayNextVideo: Boolean
        get() {
            return sharedPreferences!!.getBoolean(AUTO_PLAY_NEXT_VIDEO, false)
        }
        set(value) {
            editor!!.putBoolean(AUTO_PLAY_NEXT_VIDEO, value).commit()
        }

    var keepOtherAudio: Boolean
        get() {
            return sharedPreferences!!.getBoolean(KEEP_MUSIC, false)
        }
        set(value) {
            editor!!.putBoolean(KEEP_MUSIC, value).commit()
        }

    var privatePassword: String
        get() = sharedPreferences!!.getString(PASSWORD, "") ?: ""
        set(value) {
            editor!!.putString(PASSWORD, value).commit()
        }


    var voskModelPath: String?
        get() = sharedPreferences?.getString(MODEL_PATH, null)
        set(value) {
            editor!!.putString(MODEL_PATH, value).commit()
        }
    var lastPlay: VideoFileInfo?
        get() = get<VideoFileInfo>("LastPlay")
        set(value) {
            if (value == null) {
                editor?.remove("LastPlay")
            } else {
                put("LastPlay", value)
            }
        }
}
